<template>
  <div style="width: 100%">
    <!-- 输入区域 -->
    <el-input
      v-model="selectedAddress"
      type="textarea"
      :rows="3"
      placeholder="已选位置"
      readonly
      style="width: 100%"
    />
    <el-button @click="openMapDialog" class="mt-2">选择位置</el-button>

    <!-- 地图弹窗 -->
    <el-dialog
      v-model="dialogVisible"
      title="位置选择"
      width="60%"
      height="80%"
      @closed="destroyMap"
    >
      <div class="map-container">
        <!-- 搜索栏 -->
        <el-autocomplete
          v-model="searchText"
          placeholder="输入地址搜索"
          :fetch-suggestions="querySearch"
          @select="handleSelect"
          clearable
          class="mb-1"
        />

        <!-- 提示信息 -->
        <div class="map-wrapper" v-if="loading">地图正在初始化中......</div>

        <!-- 地图容器 -->
        <div id="tmap-container" ref="tMapContainer" class="map-wrapper"></div>

        <!-- 位置信息 -->
        <div class="position-info mt-4">
          <el-descriptions :column="1" border>
            <el-descriptions-item label="地址" label-width="120px">
              {{ currentPosition.address }}
            </el-descriptions-item>
            <el-descriptions-item label="经度" label-width="120px">
              {{ currentPosition.lng }}
            </el-descriptions-item>
            <el-descriptions-item label="纬度" label-width="120px">
              {{ currentPosition.lat }}
            </el-descriptions-item>
          </el-descriptions>
        </div>
      </div>
      <!-- 操作按钮 -->
      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="confirmSelection">确定</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
/**
 * 腾讯位置选择器
 * 坐标格式：GCJ02
 * 配置选项：ak
 * 展示组件：ra-view-tmap
 * 坐标转换：推荐 gcoord (系统已经集成)
 */
import gcoord from 'gcoord';
import { ref, reactive, watch, nextTick, shallowRef, markRaw } from 'vue'; // 确保所有 Vue API 都已导入

const key = import.meta.env.VITE_APP_MAP_TMAP_AK; // 腾讯地图密钥

// 腾讯地图实例
const mapInstance = shallowRef(null);
let geocoder = null;
const markerLayer = shallowRef(null);
let search = null;

// 响应式数据
const zoom = 16;
const loading = ref(false);
const dialogVisible = ref(false);
const searchText = ref('');
const selectedAddress = ref(''); // 用于显示在输入框中的地址文本
const currentPosition = reactive({
  address: '',
  lng: null,
  lat: null,
});

// *** 定义 props 和 emits ***
const props = defineProps({
  modelValue: {
    type: [Object, String],
    default: null,
  },
});

const emit = defineEmits(['update:modelValue']);

// *** 添加 watch 监听器以实现数据回显 ***
watch(
  () => props.modelValue,
  (newVal) => {
    if (newVal) {
      try {
        const parsedValue =
          typeof newVal === 'string' ? JSON.parse(newVal) : newVal;
        if (parsedValue && parsedValue.address) {
          selectedAddress.value = parsedValue.address; // 只显示地址
          // 同步内部状态
          currentPosition.address = parsedValue.address;
          currentPosition.lng = parsedValue.lng;
          currentPosition.lat = parsedValue.lat;
        } else {
          selectedAddress.value = '';
        }
      } catch (e) {
        console.error('解析 modelValue 失败:', e);
        selectedAddress.value = '';
      }
    } else {
      selectedAddress.value = '';
    }
  },
  { immediate: true, deep: true },
);

// 动态加载腾讯地图脚本
const loadMapScript = () => {
  return new Promise((resolve, reject) => {
    if (!key) {
      // ElMessageBox is not defined in this scope, but assuming it's globally available or imported
      // ElMessageBox.alert('请先配置腾讯地图Key', '提示');
      console.error('请先配置腾讯地图Key');
      return reject(new Error('腾讯地图Key未配置'));
    }
    if (window.TMap) return resolve(window.TMap);

    window.init = () => {
      resolve(window.TMap);
    };

    const script = document.createElement('script');
    script.src = `https://map.qq.com/api/gljs?v=2.exp&key=${key}&libraries=service&callback=init`;
    script.onerror = () => reject(new Error('腾讯地图脚本加载失败'));
    document.head.appendChild(script);
  });
};

// *** 改进地图初始化逻辑 ***
const initMap = async () => {
  loading.value = true;
  try {
    const TMap = await loadMapScript();
    await nextTick();

    let initialCenter;

    // 如果有已保存的坐标，则使用它
    if (currentPosition.lng && currentPosition.lat) {
      initialCenter = new TMap.LatLng(currentPosition.lat, currentPosition.lng);
    } else {
      // 否则，获取当前GPS位置并转换
      const gpsPosition = await getGPSLocation();
      const position = convertLocation(gpsPosition);
      initialCenter = new TMap.LatLng(position.lat, position.lng);
    }

    mapInstance.value = markRaw(
      new TMap.Map(document.getElementById('tmap-container'), {
        center: initialCenter,
        zoom: zoom,
        pitch: 0,
        rotation: 0,
      }),
    );

    // 初始化服务
    geocoder = new TMap.service.Geocoder();
    search = new TMap.service.Search({ pageSize: 10 });

    // 更新标记和地址信息
    updateMarkerAndAddress(initialCenter);

    mapInstance.value.on('click', (event) => {
      updateMarkerAndAddress(event.latLng);
    });
  } catch (error) {
    console.error('地图初始化失败:', error);
  } finally {
    loading.value = false;
  }
};

// *** 封装更新标记和地址的函数 ***
const updateMarkerAndAddress = (latLng) => {
  // 更新内部位置状态
  currentPosition.lat = latLng.getLat();
  currentPosition.lng = latLng.getLng();

  // 更新标记
  if (markerLayer.value) {
    markerLayer.value.setGeometries([{ position: latLng }]);
  } else {
    markerLayer.value = new TMap.MultiMarker({
      map: mapInstance.value,
      geometries: [{ position: latLng }],
    });
  }
  mapInstance.value.setCenter(latLng);

  // 逆地址解析
  geocoder
    .getAddress({ location: latLng })
    .then((response) => {
      const { result } = response;
      if (result && result.formatted_addresses) {
        currentPosition.address =
          result.formatted_addresses.recommend || result.address;
      }
    })
    .catch((error) => console.error('地址解析失败:', error));
};

// 搜索建议
const querySearch = (queryString, cb) => {
  if (!queryString || !search) return cb([]);
  search
    .getSuggestions({
      keyword: queryString,
      location: mapInstance.value.getCenter(),
    })
    .then((response) => {
      const suggestions = response.data.map((item) => ({
        value: `${item.title} (${item.address})`,
        ...item,
      }));
      cb(suggestions);
    })
    .catch(() => cb([]));
};

// 处理选择建议
const handleSelect = (item) => {
  const newLatLng = new TMap.LatLng(item.location.lat, item.location.lng);
  updateMarkerAndAddress(newLatLng);
};

// *** 打开弹窗的逻辑 ***
const openMapDialog = () => {
  dialogVisible.value = true;
  nextTick(() => {
    // 确保在初始化新地图前，任何旧的实例都已被销毁
    if (mapInstance.value) {
      mapInstance.value.destroy();
      mapInstance.value = null;
    }
    // 强制重新初始化地图
    initMap();
  });
};

// *** 确认选择时的数据处理 ***
const confirmSelection = () => {
  const addressData = {
    address: currentPosition.address,
    lat: currentPosition.lat,
    lng: currentPosition.lng,
  };
  // 更新输入框的显示值
  selectedAddress.value = addressData.address;
  // 向上层组件发出一个 JSON 字符串
  emit('update:modelValue', JSON.stringify(addressData));
  dialogVisible.value = false;
};

// 销毁地图
const destroyMap = () => {
  if (mapInstance.value) {
    mapInstance.value.destroy();
    mapInstance.value = null;
    markerLayer.value = null;
    geocoder = null;
    search = null;
  }
  // 不重置 currentPosition，以便下次打开时能恢复
};

// 根据浏览器获得GPS坐标
const getGPSLocation = () => {
  return new Promise((resolve) => {
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(
        (position) => {
          resolve({
            lat: position.coords.latitude,
            lng: position.coords.longitude,
          });
        },
        () => {
          resolve({ lat: 39.916527, lng: 116.397128 }); // 定位失败默认北京
        },
      );
    } else {
      resolve({ lat: 39.916527, lng: 116.397128 }); // 不支持则默认北京
    }
  });
};

// 坐标转换
const convertLocation = (point) => {
  const result = gcoord.transform(
    [point.lng, point.lat],
    gcoord.WGS84,
    gcoord.GCJ02,
  );
  return { lng: result[0], lat: result[1] };
};
</script>

<style scoped>
.map-container {
  height: 60vh;
}

.map-wrapper {
  height: 400px;
  width: 100%;
  margin: 16px 0;
}

.position-info {
  padding: 12px;
  background: #f5f7fa;
  border-radius: 4px;
}

.dialog-footer {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}
</style>
